iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 15
0
自我挑戰組

.net 後端起手式 30天認識 C# 系列 第 15

DAY 15 類別(四)

  • 分享至 

  • xImage
  •  

類別

如果把繼承也算上去的話,今天就是第六天的類別介紹了,在把類別講得更完整吧!

優化類別

還記得在 DAY 10 隨口提到的類別的基底類別是 object,所以我們自己做的類別,實作後也都有 object 的方法,但由於我們沒有在再定義內容,所以有些方法可能不能用,或者不如預期,所以今天來把這些方法弄完整。

那我們來做一個座標類別示範

class Coordinate {
  public Coordinate (decimal longitude, decimal latitude) {
    this.longitude = longitude;
    this.latitude = latitude;
  }
  public decimal longitude { get; }
  public decimal latitude { get; }
}

ToString

Coordinate c1 = new Coordinate (12.156m, 7.195m);
Console.WriteLine (c1);
Console.ReadKey ();

可以看到顯示的是demo.Program+Coordinate,因為我的命名空間是 demo,所以每個人看到的可能不一樣,但這資訊都是對我們沒有幫助的,我們希望印出的內容應該要能正確地獲得類別相關資訊,所以我們要

public override string ToString () {
  return $"longitude: {longitude}, latitude: {latitude}";
}

因為 Console.WriteLine() 方法會呼叫對象的 ToString() 方法,而 object.ToString() 預設輸出類別名稱,就會發生印出不需要的內容,所以把 ToString 改成是轉出我們的相關成員的字串,之後印出這個類別就能得到有用的資訊。

GetHashCode

因為做比較時 Equals() 會警告你需先重寫 GetHashCode(),不寫不會讓程式編譯失敗,但寫好程式的幾個要點之一就是,程式執行後不要有任何的警告。

public override int GetHashCode () {
  int hashCode = longitude.GetHashCode ();
  if (longitude.GetHashCode () != latitude.GetHashCode ()) {
    hashCode ^= latitude.GetHashCode ();
  }
  return hashCode;
}

簡單來說,只要經緯度一樣,我們就得到的 HashCode 就會是一樣,至於為什麼要用 xor(^) 來操作,因為如果是以相加減來說,較容易出現不同經緯而數值一樣的狀況,但使用 and 容易變成全是 0,or 容易全是 1,所以通常都是用 xor 來做 HashCode 的處理。

Equals

有了 GetHashCode 後,我們就可以來比較類別了。

假設我們希望兩個物件只要內容一樣就表示相等,即便參考位置不一樣

Coordinate c1 = new Coordinate (12.156m, 7.195m);
Coordinate c2 = c1;
Coordinate c3 = new Coordinate (12.156m, 7.195m);
if (Coordinate.ReferenceEquals (c1, c2)) {
  Console.WriteLine ("c1 與 c2 參考位置相等");
} 
if (c1.Equals (c2)) {
  Console.WriteLine ("c1 與 c2 相等");
}
if (Coordinate.ReferenceEquals (c1, c3)) {
  Console.WriteLine ("c1 與 c3 參考位置相等");
} 
if (c1.Equals (c3)) {
  Console.WriteLine ("c1 與 c3 相等");
} 
Console.ReadKey ();

可以看到 c1 一個也不跟 c3 相等,但我們希望 Equals() 時,顯示是 true,所以我們來改寫吧

public override bool Equals (object obj) {
  if (obj == null)
    return false;
  if (this.GetType () != obj.GetType ())
    return false;
  return this.GetHashCode () == obj.GetHashCode ();
}

首先檢查 obj 是不是 null,再檢查型別一不一樣,然後就是用我們上面做過的方法,來確認值一不一樣。

但很多人可能使用 == 來比較多過於使用 Equals(),但你會發現 (c1 == c3) 為 false ,所以我們要來重寫運算子。

比較運算子

我們就把==做成跟我們 Equals() 一樣,不管參考位置

public static bool operator == (Coordinate c1, Coordinate c2) {
  return c1.Equals (c2);
}
public static bool operator != (Coordinate c1, Coordinate c2) {
  return !c1.Equals (c2);
}

因為重寫 == 需要連同 != 一起重寫,這樣我們就可以使用 == 來做比較了。

加法類運算子

再來就是加減的時候,能夠把經緯度相加減。

public static Coordinate operator + (Coordinate c1, Coordinate c2) {
  return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude);
}
public static Coordinate operator - (Coordinate c1, Coordinate c2) {
  return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude);
}

相加減後會傳回一個新的座標類別

Coordinate c1 = new Coordinate (12.156m, 7.195m);
Coordinate c2 = new Coordinate (12.06m, 1.516m);
Console.WriteLine (c1 + c2);
Console.ReadKey ();

一些小結論

今天只重寫了我覺得比較常用到的部分,還有很多很多的運算子可以重寫,就請大家自己練習了,最後附上這次完整的範例類別程式碼。

class Coordinate {
  public Coordinate (decimal longitude, decimal latitude) {
    this.longitude = longitude;
    this.latitude = latitude;
  }
  public decimal longitude { get; }
  public decimal latitude { get; }
  public override string ToString () {
    return $"longitude: {longitude}, latitude: {latitude}";
  }
  public override int GetHashCode () {
    int hashCode = longitude.GetHashCode ();
    if (longitude.GetHashCode () != latitude.GetHashCode ()) {
      hashCode ^= latitude.GetHashCode ();
    }
    return hashCode;
  }
  public override bool Equals (object obj) {
    if (obj == null)
      return false;
    if (this.GetType () != obj.GetType ())
      return false;
    return this.GetHashCode () == obj.GetHashCode ();
  }
  public static bool operator == (Coordinate c1, Coordinate c2) {
    return c1.Equals (c2);
  }
  public static bool operator != (Coordinate c1, Coordinate c2) {
    return !c1.Equals (c2);
  }
  public static Coordinate operator + (Coordinate c1, Coordinate c2) {
    return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude);
  }
  public static Coordinate operator - (Coordinate c1, Coordinate c2) {
    return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude);
  }
}

感謝閱讀。


上一篇
DAY 14 類別(三)
下一篇
DAY 16 類別(五)
系列文
.net 後端起手式 30天認識 C# 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言